﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using DataDefine;
using ECANPort;
using Prism.Commands;
using Prism.Events;
using Prism.Ioc;
using Prism.Mvvm;
using Prism.Regions;
using UsingEventAggregator.Core;
using HCC = HandyControl.Controls;

namespace TLDNs.ViewModels
{

    public class RunParameterIndex
    {
        public int Index { get; set; }
        public RunParameter Info { get; set; }
        public RunParameterIndex(int i, RunParameter f)
        {
            Index = i;
            Info = f;
        }
    }

    public abstract class CanDevRootModelBase : CanDevViewModelBase
    {
        public CanDevRootModelBase(IContainerExtension co, IRegionManager rm, IEventAggregator ea) : base(co, rm, ea)
        {
            _ea.GetEvent<IntoRootModelEvent>().Subscribe(new Action<bool>((t) =>
            {
                IsRootModel = t;
            }));
        }

        private bool _IsRootModel = false;
        public bool IsRootModel
        {
            get { return _IsRootModel; }
            set
            {
                SetProperty(ref _IsRootModel, value);
                NotIsRootModel = !value;
                if (value)
                {
                    OnRootModelVisibility = Visibility.Visible;
                }
                else
                {
                    OnRootModelVisibility = Visibility.Collapsed;
                }
            }
        }

        private bool _NotIsRootModel = true;
        public bool NotIsRootModel
        {
            get { return _NotIsRootModel; }
            set
            {
                SetProperty(ref _NotIsRootModel, value);
            }
        }

        private Visibility _OnRootModelVisibility = Visibility.Collapsed;
        public Visibility OnRootModelVisibility
        {
            get { return _OnRootModelVisibility; }
            set
            {
                SetProperty(ref _OnRootModelVisibility, value);
            }
        }

    }


    public class ParameterEditViewModel : CanDevRootModelBase
    {
        public ParameterEditViewModel(IContainerExtension co, IRegionManager rm, IEventAggregator ea) : base(co, rm, ea)
        {
            AccessLvColl = new ObservableCollection<string>();
            AccessLvColl.AddRange(Enum.GetNames(typeof(AccessLv)));
            CurUserAccessLv = Properties.Settings.Default.CurUserAccessLv;

            ReadWriteTypeColl = new ObservableCollection<string>();
            ReadWriteTypeColl.AddRange(Enum.GetNames(typeof(VRWType)));

            TypeList = new ObservableCollection<string>();
            TypeList.AddRange(Enum.GetNames(typeof(VType)));

            SFM = SFMDocument.Create();
            int C = SFM.Devices.Length;
            for (int i = 0; i < C; i++)
            {
                // 只有Add有用
                DeviceColl.Add(new DeviceInfoIndex(i, SFM.Devices[i].DeviceInfo));
            }
            if (C > 0)
            {
                CurDevice = SFM.Devices[0];
                CurDeviceIndex = 0;
            }


            _ea.GetEvent<SaveSFMEvent>().Subscribe(SaveSFMEvent_Sub);
            _ea.GetEvent<GeneralSettingIsChangeEvent>().Subscribe(new Action<object>((obj) =>
            {
                GeneralSettingPar par = (GeneralSettingPar)obj;
                CurUserAccessLv = (AccessLv)par.UserAccessLv;

            }));
            _ea.GetEvent<SFMParameterIsChangeEvent>().Subscribe(SFMParameterIsChangeEvent_Sub);
        }

        private void SFMParameterIsChangeEvent_Sub(decimal val)
        {

        }

        private void SaveSFMEvent_Sub()
        {
            if (SFM != null)
            {
                SFM.Save();
                _ea.GetEvent<SaveSFMOkEvent>().Publish();
            }

        }

        private SFMDocument _SFM;
        public SFMDocument SFM
        {
            get { return _SFM; }
            set
            {
                SetProperty(ref _SFM, value);
                if (SFM.Devices.Length > 0)
                {
                    CurDevice = SFM.Devices[0];
                    CurDeviceIndex = 0;
                }
            }
        }
        private int CurDeviceIndex;
        private Device _CurDevice;
        public Device CurDevice
        {
            get { return _CurDevice; }
            set
            {
                SetProperty(ref _CurDevice, value);
                DataList.Clear();
                int C = value.Parameters.Length;
                for (int i = 0; i < C; i++)
                {
                    // 只有Add有用
                    DataList.Add(new RunParameterIndex(i, CurDevice.Parameters[i]));
                }
                if (DataList.Count > 0)
                    CurIndex = 0;
            }
        }

        private ObservableCollection<RunParameterIndex> _DataList = new ObservableCollection<RunParameterIndex>();
        public ObservableCollection<RunParameterIndex> DataList
        {
            get { return _DataList; }
            set { SetProperty(ref _DataList, value); }
        }


        private ObservableCollection<DeviceInfoIndex> _DeviceColl = new ObservableCollection<DeviceInfoIndex>();
        public ObservableCollection<DeviceInfoIndex> DeviceColl
        {
            get { return _DeviceColl; }
            set { SetProperty(ref _DeviceColl, value); }
        }

        private int? CurIndex = null;
        public DelegateCommand<int?> DeviceSelectChangeCommand => new DelegateCommand<int?>(DeviceSelectChangeCommand_Sub);
        private void DeviceSelectChangeCommand_Sub(int? dev)
        {
            CurIndex = dev;
            if (dev != null)
            {
                CurDevice = SFM.Devices[dev.Value];
                CurDeviceIndex = dev.Value;
                App.UIDispatcherDoAction(() => {
                    for (int i = 0; i < DeviceColl.Count; i++)
                    {
                        var tmp = DeviceColl[i];
                        tmp.FocusBackground = DeviceInfoIndex.UnFocusedBg;
                        DeviceColl[i] = tmp;
                    }
                    var tmp2 = DeviceColl[dev.Value];
                    tmp2.FocusBackground = DeviceInfoIndex.FocusedBg;
                    DeviceColl[dev.Value] = tmp2;
                });
            }

        }


        private AccessLv _CurUserAccessLv = AccessLv.User;
        public AccessLv CurUserAccessLv
        {
            get { return _CurUserAccessLv; }
            set
            {
                SetProperty(ref _CurUserAccessLv, value);
            }
        }

        public ObservableCollection<string> _ReadWriteTypeColl;
        public ObservableCollection<string> ReadWriteTypeColl
        {
            get { return _ReadWriteTypeColl; }
            set { SetProperty(ref _ReadWriteTypeColl, value); }
        }

        public ObservableCollection<string> _AccessLvColl;
        public ObservableCollection<string> AccessLvColl
        {
            get { return _AccessLvColl; }
            set { SetProperty(ref _AccessLvColl, value); }
        }

        private int _SelectIndex;
        public int SelectIndex
        {
            get { return _SelectIndex; }
            set
            {
                SetProperty(ref _SelectIndex, value);
                if (SelectIndex >= 0 && SelectIndex <= DataList.Count)
                {
                    SFMParameterIsChangeEvent.Count = 0;
                    CurParameter = DataList[SelectIndex].Info;
                    CurParameterIndex = SelectIndex;

                }

            }
        }


        private Visibility _CurParameterWriteVisibility = Visibility.Collapsed;
        public Visibility CurParameterWriteVisibility
        {
            get { return _CurParameterWriteVisibility; }
            set { SetProperty(ref _CurParameterWriteVisibility, value); }
        }

        private Visibility _CurParameterReadVisibility = Visibility.Visible;
        public Visibility CurParameterReadVisibility
        {
            get { return _CurParameterReadVisibility; }
            set { SetProperty(ref _CurParameterReadVisibility, value); }
        }

        private Visibility _HMIBytesVisibility = Visibility.Collapsed;
        public Visibility HMIBytesVisibility
        {
            get { return _HMIBytesVisibility; }
            set { SetProperty(ref _HMIBytesVisibility, value); }
        }
        private Visibility _HMIBinsVisibility = Visibility.Collapsed;
        public Visibility HMIBinsVisibility
        {
            get { return _HMIBinsVisibility; }
            set { SetProperty(ref _HMIBinsVisibility, value); }
        }
        private int _CurParameterOfByte_L;
        public int CurParameterOfByte_L
        {
            get { return _CurParameterOfByte_L; }
            set { SetProperty(ref _CurParameterOfByte_L, value); }
        }
        private int _CurParameterOfByte_H;
        public int CurParameterOfByte_H
        {
            get { return _CurParameterOfByte_H; }
            set { SetProperty(ref _CurParameterOfByte_H, value); }
        }
        private string _CurParameterBin;
        public string CurParameterBin
        {
            get { return _CurParameterBin; }
            set { SetProperty(ref _CurParameterBin, value); }
        }




        public ObservableCollection<string> _TypeList;
        public ObservableCollection<string> TypeList
        {
            get { return _TypeList; }
            set { SetProperty(ref _TypeList, value); }
        }


        private int CurParameterIndex;
        private RunParameter _CurParam;
        public RunParameter CurParameter
        {
            get { return _CurParam; }
            set
            {
                SetProperty(ref _CurParam, value);
                HMIBytesVisibility = Visibility.Collapsed;
                HMIBinsVisibility = Visibility.Collapsed;
                CurParameterWriteVisibility = Visibility.Collapsed;
                CurParameterReadVisibility = Visibility.Visible;
                if (value.ReadWriteType == VRWType.ReadWrite)
                {
                    CurParameterWriteVisibility = Visibility.Visible;
                }
                if (value.ReadWriteType == VRWType.PassivityReadOnly)
                {
                    CurParameterReadVisibility = Visibility.Collapsed; 
                }

                if (value.Type == VType.HMI_Bool)
                {
                    HMIBinsVisibility = Visibility.Visible;
                    CurParameterBin = PubMod.ValueToBinString((int)value.Value);
                }
                if (value.Type == VType.HMI_Byte)
                {
                    HMIBytesVisibility = Visibility.Visible;
                    ushort val = 0;
                    if (value.Value > ushort.MaxValue)
                        val = ushort.MaxValue;
                    else if (value.Value < ushort.MinValue)
                        val = 0;
                    else
                        val = (ushort)value.Value;

                    CurParameterOfByte_L = (val) & 0xFF;
                    CurParameterOfByte_H = (val) >> 8;
                }
               
            }
        }


        public void SaveToCanSystemEvent_Sub_WriteData(uint CanID, decimal Cur, byte st_addr)
        {
            HMIHelper.HMIDateFrame data = new HMIHelper.HMIDateFrame();
            data.Addr_Start = st_addr;
            data.ByteCount = 2;
            data.Can_Fc = Can_Fc.Write;
            if (Cur > ushort.MaxValue)
                Cur = ushort.MaxValue;
            if (Cur < ushort.MinValue)
                Cur = ushort.MinValue;
            ushort tmpCur = (ushort)Cur;

            data.Data0 = new byte[2];
            data.Data0[0] = (byte)(tmpCur & 0xFF);
            data.Data0[1] = (byte)(tmpCur >> 8);
            CAN_OBJ info = HMIHelper.CreateWrite(CanID, data);
            CanDevWriteData(info);
        }

     

        public DelegateCommand WriteOneValueCommand => new DelegateCommand(WriteOneValueCommand_Sub);
        private void WriteOneValueCommand_Sub()
        {
            if (CurParameter == null)
                return;
            if (Can1IsOnline == false && Can2IsOnline == false)
            {
                HCC.Growl.Info($"{LangDic["CanNotOnline"]}");
                return;
            }
            decimal val = CurParameter.Value;
            _ea.GetEvent<SFMParameterIsChangeEvent>().Publish(val);
            byte addr;
            switch (CurDeviceIndex)
            {
                case 0:
                    //只有类似Modbus协议定义的数据才能主动读 放在[ZhuDrive.PassivityDataItemCount-ZhuDrive.DataItemCount)之间
                    if (CurParameterIndex >= ZhuDrive.PassivityDataItemCount && CurParameterIndex < ZhuDrive.DataItemCount)
                    {
                        addr = (byte)(2 * (CurParameterIndex - ZhuDrive.PassivityDataItemCount));
                        SaveToCanSystemEvent_Sub_WriteData(ZhuDrive.ZhuDriveHMICanID, val, addr);
                    }
                    else
                    {
                        HCC.Growl.Info((string)LangDic["WriteFailed"]);
                    }
                    break;
                case 1:
                    //只有类似Modbus协议定义的数据才能主动读 
                    if (CurParameterIndex >= Pump.PassivityDataItemCount && CurParameterIndex < Pump.DataItemCount)
                    {
                        addr = (byte)(2 * (CurParameterIndex - Pump.PassivityDataItemCount));
                        SaveToCanSystemEvent_Sub_WriteData(Pump.PumpHMICanID, val, addr);
                    }
                    else
                    {
                        HCC.Growl.Info((string)LangDic["WriteFailed"]);
                    }

                    break;
                default:
                    HCC.Growl.Info((string)LangDic["WriteFailed"]);
                    break;
            }
        }

        public void SaveToCanSystemEvent_Sub_ReadData(uint CanID, byte st_addr)
        {
            HMIHelper.HMIDateFrame data = new HMIHelper.HMIDateFrame();
            data.Addr_Start = st_addr;
            data.ByteCount = 2;
            data.Can_Fc = Can_Fc.Read;
            CAN_OBJ info = HMIHelper.CreateRead(CanID, data);
            CanDevWriteData(info);
        }

        /// <summary>
        /// 读一个参数自动刷新
        /// 方法1:
        /// 1.ReadOneValueCommandAutoReflash
        /// 2.TLDCanDataSet.SyncOneDataNextRecv
        /// 3.Resolve
        /// 4.CheckReport
        /// 5.ReadOneValueCommand_CB
        /// 方法2:
        /// 1.延迟500ms
        /// 2.ReadOneValueCommand_CB
        /// 3.延迟500ms
        /// 3.ReadOneValueCommand_CB
        /// </summary>
        /// <param name="devIncdex"></param>
        /// <param name="ParIndex"></param>
        private void ReadOneValueCommandAutoReflash(int devIncdex, int ParIndex)
        {
            TLDCanDataSet.SyncOneDataNextRecvReqRspCb RRCB = new TLDCanDataSet.SyncOneDataNextRecvReqRspCb();
            RRCB.pa.devIndex = devIncdex;
            RRCB.pa.parIndex = ParIndex;
            RRCB.cb = new Action<TLDCanDataSet.SyncOneDataNextRecvReqRsp>(ReadOneValueCommand_CB);
            TLDCanDataSet.SyncOneDataOnNextRecv(RRCB);
        }

        private void ReadOneValueCommand_CB(TLDCanDataSet.SyncOneDataNextRecvReqRsp obj)
        {
            TLDCanDataSet.SyncOneData(TLDCanDataSet.InherDoc, SFM, obj.devIndex, obj.parIndex);
        }

        private void ReadOneValueCommandAutoReflash2(int devIndex, int parIndex)
        {
            Task tk = new Task(() =>
            {
                Thread.Sleep(500);
                TLDCanDataSet.SyncOneData(TLDCanDataSet.InherDoc, SFM, devIndex, parIndex);
                Thread.Sleep(500);
                TLDCanDataSet.SyncOneData(TLDCanDataSet.InherDoc, SFM, devIndex, parIndex);
            });
            tk.Start();
        }

        public DelegateCommand ReadOneValueCommand => new DelegateCommand(ReadOneValueCommand_Sub);
        private void ReadOneValueCommand_Sub()
        {
            if (CurParameter == null)
                return;
            decimal val = CurParameter.Value;
            if (Can1IsOnline == false && Can2IsOnline == false)
            {
                HCC.Growl.Info($"{LangDic["CanNotOnline"]}");
                return;
            }

            byte addr;
            switch (CurDeviceIndex)
            {
                case 0:
                    if (CurParameterIndex >= ZhuDrive.PassivityDataItemCount && CurParameterIndex < ZhuDrive.DataItemCount)
                    {
                        ReadOneValueCommandAutoReflash(CurDeviceIndex, CurParameterIndex);

                        addr = (byte)(2 * (CurParameterIndex - ZhuDrive.PassivityDataItemCount));
                        SaveToCanSystemEvent_Sub_ReadData(ZhuDrive.ZhuDriveHMICanID, addr);
                    }
                    else
                    {
                        HCC.Growl.Info((string)LangDic["ReadFailed"]);
                    }
                    break;
                case 1:
                    if (CurParameterIndex >= Pump.PassivityDataItemCount && CurParameterIndex < Pump.DataItemCount)
                    {
                        ReadOneValueCommandAutoReflash(CurDeviceIndex, CurParameterIndex);

                        addr = (byte)(2 * (CurParameterIndex - Pump.PassivityDataItemCount));
                        SaveToCanSystemEvent_Sub_ReadData(Pump.PumpHMICanID, addr);
                    }
                    else
                    {
                        HCC.Growl.Info((string)LangDic["ReadFailed"]);
                    }
                    break;
                default:
                    HCC.Growl.Info((string)LangDic["ReadFailed"]);
                    break;
            }

        }

        protected override void SFMFileIsReLoaded()
        {
            SFM = SFMDocument.Create();
            DeviceColl.Clear();
            DataList.Clear();
            int C = SFM.Devices.Length;
            for (int i = 0; i < C; i++)
            {
                // 只有Add有用
                DeviceColl.Add(new DeviceInfoIndex(i, SFM.Devices[i].DeviceInfo));
            }
            if (C > 0)
                CurDevice = SFM.Devices[0];
        }

        public DelegateCommand<int?> DeleteCurLineCommand => new DelegateCommand<int?>(DeleteCurLineCommand_Sub);
        private void DeleteCurLineCommand_Sub(int? TabIndex)
        {
            if (TabIndex != null && TabIndex.Value >= 0)
            {
                DataList.RemoveAt(TabIndex.Value);
                RunParameterIndex[] tmp = DataList.ToArray();
                CurDevice.Parameters = (from x in tmp select x.Info).ToArray();
            }

        }

        public DelegateCommand AddOneLineCommand => new DelegateCommand(AddOneLineCommand_Sub);
        private void AddOneLineCommand_Sub()
        {
            var li = CurDevice.Parameters.ToList();
            li.Add(new RunParameter());
            CurDevice.Parameters = li.ToArray();
        }

        private DataGrid dg_Device;
        public DelegateCommand<DataGrid> RegeditDeviceDataGridCommand => new DelegateCommand<DataGrid>(RegeditDeviceDataGridCommand_Sub);
        private void RegeditDeviceDataGridCommand_Sub(DataGrid g)
        {
            if (g != null)
            {
                dg_Device = g;
            }
        }
        

    }
}

